package me.pearjelly.pmc.search;

import java.io.File;
import java.io.IOException;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

import me.pearjelly.pmc.util.ConfigManager;
import me.pearjelly.pmc.util.Logger;

import org.apache.commons.lang.StringUtils;
import org.apache.lucene.index.CorruptIndexException;
import org.apache.lucene.search.IndexSearcher;
import org.apache.lucene.store.FSDirectory;

/**
 * @author xiaobinghan
 * Singleton IndexSearcher管理器</br>
 * daemon监控索引文件更新</br>
 * 用InstanceHolder实现线程安全的lazy load</br>
 */
public class SearcherManager {
	public static IndexSearcher instance() {
		return InstanceHolder.indexSearcher;
	}
	private static class InstanceHolder {
		private static final Logger log = new Logger();
		private static final String INDEXDIR =  "/opt/pms/index/data";
		private static IndexSearcher indexSearcher = openIndexSearcher();
		private static Thread daemon;
		
		public static IndexSearcher openIndexSearcher(){			
			try {
				String indexDir = ConfigManager.instance().getRealTimeProperty(
						"search", "manager.indexDir");
				if(StringUtils.isEmpty(indexDir)){
					indexDir = InstanceHolder.INDEXDIR;
				}
				IndexSearcher indexSearcher = new IndexSearcher(FSDirectory.open(new File(
						indexDir)), true);
				log.info("Open IndexSearcher:%s, index directory:%s",indexSearcher.toString(),indexDir);
				return indexSearcher;
			} catch (CorruptIndexException e) {
				log.error("Open IndexSearcher CorruptIndexException:%s", e.getMessage());
			} catch (IOException e) {
				log.error("Open IndexSearcher IOException:%s", e.getMessage());
			} 
			return null;
		}
		static {
			daemon = new Thread(new Runnable() {
				private Map<String,Long> modified = new HashMap<String, Long>();
				private File getIndexDirectory(){
					String indexDir = ConfigManager.instance().getRealTimeProperty(
							"search", "manager.indexDir");
					if(StringUtils.isEmpty(indexDir)){
						indexDir = InstanceHolder.INDEXDIR;
					}
					File directory = new File(indexDir);
					
					if(directory.isDirectory()){
						File lock = new File(new StringBuilder(indexDir).append(File.separatorChar).append("write.lock").toString());
						if(!lock.exists()){
							return directory;
						}else{
							log.info("Index directory %s is locked.", indexDir);
						}						
					}else{
						log.error("Index directory File %s is not a directory.", indexDir);
					}
					return null;
				}
				private void initModified(){
					File directory = getIndexDirectory();
					File[] files = directory.listFiles();
					for (File file : files) {
						modified.put(file.getName(), file.lastModified());
					}
				}
				@Override
				public void run() {
					log.info("Index daemon run.");
					initModified();
					while(Boolean.TRUE){
						Long checkinterval;
						try {
							checkinterval = Long.parseLong(ConfigManager
									.instance().getRealTimeProperty("search",
											"manager.checkinterval"));
						} catch (NumberFormatException e) {
							checkinterval = 60000L;
						}
						try {
							Thread.sleep(checkinterval);
						} catch (InterruptedException e) {
							log.error("Daemon Thread sleep InterruptedException:%s", e.getMessage());
						}
						String daemonFlag = ConfigManager.instance().getRealTimeProperty(
								"search", "manager.daemon");
						if("true".equalsIgnoreCase(daemonFlag) || "on".equalsIgnoreCase(daemonFlag)){
							log.debug("Daemon say: Start checking index directory.");
							File directory = getIndexDirectory();
							if(directory != null){
								boolean reopenFlag = Boolean.FALSE;
								Map<String,Long> tmpModified = new HashMap<String, Long>();
								File[] files = directory.listFiles();
								for (File file : files) {
									String fileName = file.getName();
									Long newModifyTime = file.lastModified();
									tmpModified.put(fileName, newModifyTime);									
									if(!modified.keySet().contains(fileName)){
										log.debug("Daemon say: Index file %s is created at %s.",fileName, new Date(newModifyTime).toString());
										reopenFlag = Boolean.TRUE;
									}else{									
										Long oldModifyTime = modified.get(fileName);
										if(newModifyTime.compareTo(oldModifyTime) > 0){
											log.debug("Daemon say: Index file %s is modified at %s.",fileName, new Date(newModifyTime).toString());
											reopenFlag = Boolean.TRUE;
										}
										modified.remove(fileName);
									}
								}
								for(String fileName : modified.keySet()){
									log.debug("Daemon say: Index file %s is deleted.",fileName);
									reopenFlag = Boolean.TRUE;
								}
								modified = tmpModified;								
								if(reopenFlag){
									log.info("Daemon say: Files in index directory are changed. Reopen index directory.");
//									IndexSearcher tmpIndexSearcher = InstanceHolder.indexSearcher;
									IndexSearcher indexSearcher = InstanceHolder.openIndexSearcher();
									if(indexSearcher!=null){
										InstanceHolder.indexSearcher =  indexSearcher;
									}
//									try {
									//ֱ�ӹر�������
//										tmpIndexSearcher.close();
//									} catch (IOException e) {
//										log.error("Close IndexSearcher IOException:%s", e.getMessage());
//									}
								}
							}
						}else{
							log.debug("Daemon flag isnot on.");
						}
					}
				}
			});
			daemon.start();
		}		
	}
}
